﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.IO;
using System.Windows;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Threading;
using System.ComponentModel;
using System.Globalization;

namespace VKontakteClient
{
    /// <summary>
    /// Класс кнопки навигации вконтакта
    /// </summary>
    class VKButton
    {
        /// <summary>
        /// Текст на кнопке
        /// </summary>
        public string Text
        {
            get;
            set;
        }

        /// <summary>
        /// Ссыка куда переход
        /// </summary>
        public string Url
        {
            get;
            set;
        }
    }

    /// <summary>
    /// Класс реализующий низкоуровневое API с VKontakte
    /// </summary>
    class   VKontakteAPI
    {
        /// <summary>
        /// Удаляет HTML-тэги из строки
        /// </summary>
        /// <param name="Value">Строка из которой надо удалить HTML-тэг</param>
        /// <returns>Результирующая строка</returns>
        public static string StripTags(string Value)
        {
            if (Value == null) return null;
            while (Value.Contains('<') && Value.Contains('>')) Value = Value.Remove(Math.Max(0,Value.IndexOf('<')), Math.Min(Value.IndexOf('>') - Value.IndexOf('<') + 1, Value.Length - Math.Max(0,Value.IndexOf('<'))));
            var result= System.Web.HttpUtility.HtmlDecode(Value).Replace("&quot;","\"").Replace("&gt",">").Replace("&lt","<");
            return result;
        }

        /// <summary>
        /// APIлка для установки кукиса в ИЕ.
        /// </summary>
        /// <param name="url">Сервер</param>
        /// <param name="cookieName">Имя плюшки</param>
        /// <param name="cookieData">Значение плюшки</param>
        /// <returns></returns>
        [DllImport("wininet.dll", EntryPoint = "InternetSetCookie", ExactSpelling = false, CharSet = CharSet.Unicode, SetLastError = true)]
        static extern bool InternetSetCookie(string url, string cookieName, string cookieData);

        /// <summary>
        /// APIлка для получения плюшки из IE
        /// </summary>
        /// <param name="url">Серве</param>
        /// <param name="cookieName">Имя плюшки</param>
        /// <param name="cookieData">Значение плюшки</param>
        /// <param name="size">Размер плюшки</param>
        /// <returns></returns>
        [DllImport("wininet.dll", EntryPoint = "InternetGetCookie", ExactSpelling = false, CharSet = CharSet.Unicode, SetLastError = true)]
        static extern bool InternetGetCookie(string url, string cookieName, StringBuilder cookieData, ref int size);

        /// <summary>
        /// Получает набор плюшек вконтакта из ИЕ.
        /// </summary>
        public static CookieCollection GetCookies()
        {
#if DEBUG
            DebugLog.Dump("GetCookies()");
#endif
            Uri url = new Uri("http://vkontakte.ru/", UriKind.Absolute);
            CookieContainer cookies = new CookieContainer();
            int datasize = 256;
            StringBuilder cookieData = new StringBuilder(datasize);
            if (!InternetGetCookie(url.ToString(), null, cookieData,
              ref datasize))
            {
                if (datasize < 0)
                    return null;
                cookieData = new StringBuilder(datasize);
                if (!InternetGetCookie(url.ToString(), null, cookieData,
                  ref datasize))
                    return null;
            }
            if (cookieData.Length > 0)
                cookies.SetCookies(url, cookieData.ToString().Replace(';', ','));
            return cookies.GetCookies(url);
        }

        /// <summary>
        /// Устанавливает плюшку в ИЕ для вконтакта.
        /// </summary>
        /// <param name="cookieName">Имя плюшки</param>
        /// <param name="cookieData">Значение плюшки</param>
        public static void SetCookie(Cookie cookie)
        {
            if (!InternetSetCookie("http://vkontakte.ru", null, cookie.ToString()))
            {
                MessageBox.Show("Exception setting cookie: Win32 Error code=" + Marshal.GetLastWin32Error());
            }
        }

        /// <summary>
        /// Получает HttpWebRequest для вконтакта по заданной ссылке
        /// </summary>
        /// <param name="Url">Относительная ссылка, например "profile.php"</param>
        /// <returns>Возвращает HttpWebRequest</returns>
        public static HttpWebRequest GetWebRequest(string Url)
        {
            return GetWebRequest(Url, null);
        }

        /// <summary>
        /// Словарь в котором храним время последнего запроса для каждого типа страниц. А то контакт любит ругаться если загружается более одной однотипной страницы в секунду.
        /// </summary>
        private static Dictionary<string, DateTime> _tempdict;

        /// <summary>
        /// Свойство, реализующее ленивую инициализацию словаря для хранения времени последних запросов.
        /// </summary>
        private static Dictionary<string,DateTime> LastRequestTime
        {
            get
            {
                if (_tempdict == null) _tempdict = new Dictionary<string, DateTime>();
                return _tempdict;
            }
        }

        /// <summary>
        /// Хитрый объект используемый для блокировки(lock)
        /// </summary>
        private static object Obj = new object();

        /// <summary>
        /// Получает HttpWebRequest для вконтакта по заданной ссылке
        /// </summary>
        /// <param name="Url">Относительная ссылка, например "profile.php"</param>
        /// <param name="data">Данные для POST-запроса</param>
        /// <returns>Возвращает HttpWebRequest</returns>
        public static HttpWebRequest GetWebRequest(string Url, byte[] data)
        {
            if (App.IsOffline) return null;
            if (string.IsNullOrEmpty(Url)) return null;
            lock (Obj)
            {
                string MiniUrl = Url.Contains("?")?Url.Remove(Url.IndexOf('?')):Url;
                if (MiniUrl != null)
                {
                    if (MiniUrl.StartsWith("id", StringComparison.CurrentCulture)) MiniUrl = "ID";
                    if (LastRequestTime.Keys.Contains(MiniUrl) && DateTime.Now - LastRequestTime[MiniUrl] < new TimeSpan(0, 0, 0, 1, 300))
                        Thread.Sleep(1500);
                }
                LastRequestTime[MiniUrl]=DateTime.Now;
                HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create("http://vkontakte.ru/" + Url);
                //wr.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5 (.NET CLR 3.5.30729)";
                if (wr == null) return null;
                wr.AllowAutoRedirect = false;
                wr.Credentials = CredentialCache.DefaultCredentials;
                wr.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                wr.Headers["Accept-Language"] = "ru,en-us;q=0.7,en;q=0.3";
                wr.Headers["Accept-Charset"] = "windows-1251,utf-8;q=0.7,*;q=0.7";
                wr.KeepAlive = true;
                wr.Timeout = 50000;
                wr.Headers["Keep-Alive"] = "300";
                var S = "";
                foreach (Cookie v in App.Settings.Cookies)
                    if (v != null)
                        S += v.ToString() + ";";
                wr.Headers.Add(HttpRequestHeader.Cookie, S);
                wr.ProtocolVersion = new Version("1.1");
                if (data != null)
                {
                    wr.ContentType = "application/x-www-form-urlencoded";
                    wr.ContentLength = data.Length;
                    wr.Method = "POST";
                    wr.ReadWriteTimeout = 5000;
                    wr.AllowWriteStreamBuffering = true;
                    Stream newStream = wr.GetRequestStream();
                    if (newStream != null)
                    {
                        newStream.Write(data, 0, data.Length);
                        newStream.Close();
                    }
                }
                else
                    wr.Method = "GET";
                return wr;
            }
        }
        
        /// <summary>
        /// Получает строку, с содержимым страницы по заданному запросу
        /// </summary>
        /// <param name="wr">WebResponse из которого загружается страница</param>
        /// <param name="RawReturn">Сырой ответ или мессага об ошибке</param>
        /// <returns>Возвращает строку с содержимым страницы</returns>
        public static string GetResponse(HttpWebResponse wr, bool RawReturn)
        {
            if (App.IsOffline || wr==null) return null;
            var resStream = wr.GetResponseStream();
            var s = new BinaryReader(resStream);
            var TempStream = new MemoryStream();
            byte[] buffer = new byte[4096];
            int L = 0;
            while ((L = s.Read(buffer, 0, 4096)) > 0)
            {
                TempStream.Write(buffer, 0, L);
            }
            var Bytes = new byte[TempStream.Length];
            TempStream.Position = 0;
            TempStream.Read(Bytes, 0, (int)TempStream.Length);
            TempStream.Close();
            var result = Encoding.GetEncoding(1251).GetString(Bytes);
            s.Close();
            resStream.Close();
#if DEBUG
            DebugLog.Dump(result);
#endif
            if (!RawReturn)
            {
                if (result.IndexOf("<div id='error'", StringComparison.CurrentCulture) > 0)
                {
                    var Error = result.Remove(0, result.IndexOf("<div id='error'", StringComparison.CurrentCulture));
                    Error = Error.Remove(0, Error.IndexOf('>') + 1);
                    Error = Error.Remove(Error.IndexOf("</div>", StringComparison.CurrentCulture));
                    return "Ошибка: " + Error;
                }
                if (result.IndexOf("<div id='message'", StringComparison.CurrentCulture) > 0)
                {
                    var Error = result.Remove(0, result.IndexOf("<div id='message'", StringComparison.CurrentCulture));
                    Error = Error.Remove(0, Error.IndexOf('>') + 1);
                    Error = Error.Remove(Error.IndexOf("</div>", StringComparison.CurrentCulture));
                    return "Ошибка: " + Error;
                }
                if (result.Contains(@"<div id=""pageBody"" class=""pageBody"">"))
                {
                    var Converted = result.Remove(0, result.IndexOf(@"<div id=""pageBody"" class=""pageBody"">", StringComparison.CurrentCulture));
                    var X = Converted.Substring(Math.Max(0,Converted.IndexOf("<h1>", StringComparison.CurrentCulture) + 4), Converted.IndexOf("</h1>", StringComparison.CurrentCulture) - Converted.IndexOf("<h1>", StringComparison.CurrentCulture) - 4).Trim();
                    if (X.StartsWith("Ошибка", StringComparison.CurrentCulture))
                    {
                        var err = Converted.Remove(0, Math.Min(Converted.IndexOf("<div class=\"simpleHeader\">", StringComparison.CurrentCulture),Converted.Length));
                        err = err.Remove(err.IndexOf("</div>", StringComparison.CurrentCulture)); err = StripTags(err);
                        return "Ошибка: \r\n" + err + "\r\n";
                    }
                }
            }
            return result;

        }

        /// <summary>
        /// Список визуальных кнопок переходов
        /// </summary>
        private static ObservableCollection<VKButton> _buttons;

        /// <summary>
        /// Свойство-список визуальных кнопок переходов, реализует ленивую инициализацию
        /// </summary>
        public static ObservableCollection<VKButton> VKButtons
        {
            get
            {
                if (_buttons != null) return _buttons;
                _buttons = new ObservableCollection<VKButton>();
                GetVKButtons();
                return VKButtons;
            }
        }

        /// <summary>
        /// Получает строку с содержимым страницы по ссылке
        /// </summary>
        /// <param name="Uri">Относительная ссылка</param>
        /// <param name="TryCount">Количество повторов</param>
        /// <returns>Строка с содержимым страницы</returns>
        public static string GetPage(string Uri, int TryCount)
        {
            return GetPage(Uri, TryCount, false);
        }

        /// <summary>
        /// Получает строку с содержимым страницы по ссылке
        /// </summary>
        /// <param name="Uri">Относительная ссылка</param>
        /// <param name="TryCount">Количество повторов</param>
        /// <param name="RawReturn">Сырой ответ</param>
        /// <returns>Строка с содержимым страницы</returns>
        public static string GetPage(string Uri, int TryCount, bool RawReturn)
        {
            try
            {
                if (App.IsOffline) return null;
                var wr = GetWebRequest(Uri);
                wr.AllowAutoRedirect = true;
                var wrr = wr.GetResponse();
                var str = GetResponse((HttpWebResponse)wrr, RawReturn);
                wrr.Close();
                if (TryCount > 0 && str.StartsWith("Ошибка: ", StringComparison.CurrentCulture))
                {
                    if (str == "Ошибка: \r\nСтраница скрыта\r\n") return str;
                    Thread.Sleep(1000);
                    return GetPage(Uri, TryCount - 1);
                }
                return str;
            }
            catch
            {
                if (TryCount > 0) return GetPage(Uri, TryCount - 1, RawReturn);
                else return "Ошибка: не удалось соединиться с сервером";
            }
        }

        /// <summary>
        /// Получает список друзей для конкретного пользователя
        /// </summary>
        /// <param name="user">Пользователь, для которого надо получить список друзей</param>
        /// <returns>Поток обработки</returns>
        public static Thread UpdateUserFriends(Human user)
        {
            var LThread = new Thread(() =>
            {
                try
                {
                    var Converted = VKontakteAPI.GetPage("friend.php?id=" + user.Id, 2);
                    List<Human> l = new List<Human>();
                    if (Converted.StartsWith("Ошибка", StringComparison.CurrentCulture))
                    {
                        if (Converted == "Ошибка: \r\nСтраница скрыта\r\n")
                            App.SqlCeAPI.PropertyLoaded(user.Id, "Friends");
                        return;
                    }
                    Converted = Converted.Remove(0, Converted.IndexOf("<script>friendsInfo = {", StringComparison.CurrentCulture));
                    Converted = Converted.Remove(Converted.IndexOf("univs:", StringComparison.CurrentCulture));
                    Converted = Converted.Remove(0, Converted.IndexOf("[[", StringComparison.CurrentCulture) + 1);
                    Converted = Converted.Remove(Converted.IndexOf("]]", StringComparison.CurrentCulture));
                    var friends = Converted.Split(new char[] { '[' }).Where(v => !String.IsNullOrEmpty(v));
                    foreach (var v in friends)
                    {
                        int ID = int.Parse(v.Remove(v.IndexOf(',')), CultureInfo.InvariantCulture);
                        Human h = Human.GetHuman(ID, false);
                        h.UpdateTime = DateTime.Now;
                        string s = v;
                        while (s.Contains("{"))
                        {
                            string part = s.Substring(s.IndexOf('{'), s.IndexOf('}') - s.IndexOf('{') + 1);
                            s = s.Remove(s.IndexOf('{'), s.IndexOf('}') - s.IndexOf('{') + 1);
                            if (part.Contains("f:'"))
                            {
                                string Family = part.Remove(0, part.IndexOf("f:'", StringComparison.CurrentCulture) + 3);
                                Family = Family.Remove(Family.IndexOf('\''));
                                h.FirstName = Family;
                            }
                            if (part.Contains("l:'"))
                            {
                                string Family = part.Remove(0, part.IndexOf("l:'", StringComparison.CurrentCulture) + 3);
                                Family = Family.Remove(Family.IndexOf('\''));
                                h.LastName = Family;
                            }
                            if (part.Contains("p:'"))
                            {
                                string Family = part.Remove(0, part.IndexOf("p:'", StringComparison.CurrentCulture) + 3);
                                Family = Family.Remove(Family.IndexOf('\''));
                                Uri URL = null;
                                if (Family.StartsWith("images/question", StringComparison.CurrentCulture)) Family = "http://vkontakte.ru/images/question_b.gif";
                                if (!Family.EndsWith("_null.gif", StringComparison.CurrentCulture))
                                {
                                    URL = new Uri(Family, UriKind.Absolute);
                                    h.Photo = new Downloadable() { Uri = URL };
                                }
                            }
                        }
                        l.Add(h);
                    }
                    if (user.Friends == null || !l.SequenceEqual(user.Friends))
                        user.Friends = l;
                }
                catch(Exception e)
                {
                    DebugLog.DebugException(e);
                }
            });
            return LThread;
        }

        /// <summary>
        /// Парсит HTML в список аудиозаписей
        /// </summary>
        /// <param name="Converted">HTML-код</param>
        /// <param name="doPaging">Обрабатывать ли многостраничность</param>
        public static IEnumerable<Audio> ParseHTMLToAudio(string Converted, bool doPaging)
        {
            if (Converted == null) return null;
            List<Audio> local = new List<Audio>();
            if (doPaging)
            {
                if (Converted.Contains("pagination.init"))
                {
                    var s_ID = Converted.Remove(0, Math.Min(Converted.IndexOf("pagination.init", StringComparison.CurrentCulture),Converted.Length));
                    var add = "";
                    if (s_ID.Contains("\"gid\":"))
                    {
                        s_ID = s_ID.Remove(0, Math.Min(s_ID.IndexOf("\"gid\":", StringComparison.CurrentCulture) + 6,s_ID.Length));
                        add = "g";
                    }
                    else
                    {
                        s_ID = s_ID.Remove(0, Math.Min(s_ID.IndexOf("\"id\":", StringComparison.CurrentCulture) + 5,s_ID.Length));
                    }
                    s_ID = s_ID.Remove(s_ID.IndexOf(','));
                    if (s_ID != null)
                    {
                        s_ID = s_ID.Replace("\"", "");
                    }
                    int ID = int.Parse(s_ID, CultureInfo.InvariantCulture);
                    if (Converted!=null && Converted.Contains("<div class=\"commentsPagesWrap standard\">"))
                    {
                        var t = Converted.Remove(0, Math.Min(Converted.IndexOf("<div class=\"commentsPagesWrap standard\">", StringComparison.CurrentCulture),Converted.Length));
                        t = t.Remove(t.IndexOf("<div id=\"audios\" style=\"padding: 5px 30px\">", StringComparison.CurrentCulture));
                        while (t!=null && t.Contains("javascript: getPageContent"))
                        {
                            t = t.Remove(0, t.IndexOf("javascript: getPageContent", StringComparison.CurrentCulture) + 1);
                            var s = t.Remove(0, t.IndexOf('(') + 1);
                            s = s.Remove(s.IndexOf(')'));
                            var ids = s.Split(new char[] { ',' }).Select(v => int.Parse(v, CultureInfo.InvariantCulture)).ToArray();
                            string dl = GetPage("audio.php?act=getpages&"+add+"id=" + ID + "&offset=" + ids[0], 2);
                            if (!dl.StartsWith("Ошибка", StringComparison.CurrentCulture)) Converted += dl;
                        }
                    }
                }
            }
            while (Converted!=null && Converted.Contains("<div class=\"audioRow"))
            {
                Audio audio = new Audio();
                Converted = Converted.Remove(0, Math.Min(Converted.IndexOf("<div class=\"audioRow", StringComparison.CurrentCulture) + 1,Converted.Length));
                var S = Converted.Remove(0, Converted.IndexOf("return operate(", StringComparison.CurrentCulture));
                S = S.Remove(0, S.IndexOf('(') + 1);
                S = S.Remove(S.IndexOf(')'));
                var d = S.Split(new char[] { ',' });
                if (d.Length > 4)
                {
                    string Url = "http://cs" + d[1] + ".vkontakte.ru/u" + d[2] + "/audio/" + d[3].Replace("'", "") + ".mp3";
                    audio.MaximumProgress = int.Parse(d[4], CultureInfo.InvariantCulture);
                    audio.File.Uri = new Uri(Url, UriKind.Absolute);
                    S = Converted;
                    S = S.Remove(0, S.IndexOf("<b id=\"performer", StringComparison.CurrentCulture));
                    S = S.Remove(0, S.IndexOf('>') + 1);
                    audio.Name = S.Remove(S.IndexOf('<'));
                    audio.Name += " - ";
                    S = S.Remove(0, S.IndexOf("<span id=\"title", StringComparison.CurrentCulture));
                    S = S.Remove(0, S.IndexOf('>') + 1);
                    if (S.StartsWith("<a href='javascript: showLyrics", StringComparison.CurrentCulture))
                    {
                        var Lid = S.Remove(0, S.IndexOf('(') + 1);
                        Lid = Lid.Remove(Lid.IndexOf(')'));
                        Lid = Lid.Remove(0, Lid.LastIndexOf(',') + 1);
                        var wr = VKontakteAPI.GetWebRequest("audio.php", System.Text.Encoding.ASCII.GetBytes("act=getLyrics&lid=" + Lid)).GetResponse() as HttpWebResponse;
                        if (wr != null)
                        {
                            var res = VKontakteAPI.GetResponse(wr, true);
                            wr.Close();
                            res = System.Web.HttpUtility.HtmlDecode(res).Replace("<br>", "\r\n");
                            audio.Lyrics = res;
                            S = S.Remove(0, S.IndexOf('>') + 1);
                        }
                    }
                    audio.Name += S.Remove(S.IndexOf('<'));
                    audio.Name = System.Web.HttpUtility.HtmlDecode(audio.Name);
                    local.Add(audio);
                }
            }
            return local;
        }

        /// <summary>
        /// Парсит HTML в список аудиозаписей
        /// </summary>
        /// <param name="Converted">HTML-код</param>
        public static IEnumerable<Audio> ParseHTMLToAudio(string Converted)
        {
            if (Converted == null) return null;
            return ParseHTMLToAudio(Converted, true);
        }

        /// <summary>
        /// Получает список аудиозаписей пользователя.
        /// </summary>
        /// <param name="user">Человек, для которого надо обновить список аудиозаписей</param>
        static List<Human> loading = new List<Human>();
        public static Thread GetUserAudios(Human user)
        {
            var LThread = new Thread(() =>
            {
                if (loading.Contains(user)) return;
                loading.Add(user);
                var Converted = VKontakteAPI.GetPage("audio.php?id=" + user.Id, 2);
                if (!Converted.StartsWith("Ошибка", StringComparison.CurrentCulture))
                    user.Audio = ParseHTMLToAudio(Converted);
                loading.Remove(user);
            });
            return LThread;
        }

        private static void ParseClosedProfileHTML(Human user, string Converted)
        {
            user.ClosedProfile = true;
            var X = Converted;
            X = X.Remove(0, X.IndexOf("<div class=\"result clearFix\">", StringComparison.CurrentCulture));
            var U = X.Remove(X.IndexOf("<dt>Имя:</dt>", StringComparison.CurrentCulture));
            if (U.IndexOf("http", StringComparison.CurrentCulture) != -1)
            {
                U = U.Remove(0, U.IndexOf("src=", StringComparison.CurrentCultureIgnoreCase) + 4);
                var Url = U.Substring(0, U.IndexOf(" ", StringComparison.CurrentCulture));
                Url = Url.Replace("\"", "").Replace("'", "");
                if (Url.StartsWith("images/question", StringComparison.CurrentCulture)) Url = "http://vkontakte.ru/images/question_b.gif";
                if (!Url.EndsWith("_null.gif", StringComparison.CurrentCulture))
                    user.Photo = new Downloadable() { Uri = new Uri(Url, UriKind.Absolute) };
            }
            X = X.Remove(0, X.IndexOf("<div style=\"overflow: hidden;\">", StringComparison.CurrentCulture));
            X = X.Remove(0, X.IndexOf('>') + 1);
            var FIO = X.Substring(0, X.IndexOf('<')).Trim();
            user.FirstName = FIO.Substring(0, FIO.IndexOf(' '));
            user.LastName = FIO.Substring(FIO.LastIndexOf(' '));
            user.Nickname = FIO.Substring(FIO.IndexOf(' '), FIO.LastIndexOf(' ') - FIO.IndexOf(' '));
            if (X.IndexOf("<dd style=\"width: 260px; overflow: hidden;\">", StringComparison.CurrentCulture) != -1)
            {
                X = X.Remove(0, X.IndexOf("<dd style=\"width: 260px; overflow: hidden;\">", StringComparison.CurrentCulture));
                X = X.Remove(0, X.IndexOf('>') + 1);
                var VUZ = X.Remove(X.IndexOf('<'));
                var Q = new HighEducation();
                Q.University = VUZ;
                if (VUZ.Contains('\''))
                {
                    Q.University = Q.University.Remove(Q.University.IndexOf('\'')).Trim();
                    Q.Finish = new DateTime(2000 + int.Parse(VUZ.Remove(0, VUZ.IndexOf('\'') + 1), CultureInfo.InvariantCulture), 1, 1);
                }
                if (X.IndexOf("<dd style=\"width: 260px; overflow: hidden;\">", StringComparison.CurrentCulture) != -1)
                {
                    X = X.Remove(0, X.IndexOf("<dd style=\"width: 260px; overflow: hidden;\">", StringComparison.CurrentCulture));
                    X = X.Remove(0, X.IndexOf('>') + 1);
                    var FAK = X.Remove(X.IndexOf('<'));
                    Q.Faculty = FAK;
                }
                if (user.HighEducation == null) user.HighEducation = new List<HighEducation>();
                if (user.HighEducation.Where(v => v.Equals(user.HighEducation)).Count() == 0) user.HighEducation.Add(Q);
            }
        }

        private static void ParseOpenProfileHTML(Human user, string Converted)
        {
            user.ClosedProfile = false;
            var X = Converted.Substring(Converted.IndexOf("<h1>", StringComparison.CurrentCulture) + 4, Converted.IndexOf("</h1>", StringComparison.CurrentCulture) - Converted.IndexOf("<h1>", StringComparison.CurrentCulture) - 4).Trim();
            if (X.Contains("Online"))
            {
                user.IsOnline = true;
                X = X.Remove(X.IndexOf("<b>", StringComparison.CurrentCulture), X.IndexOf("</b>", StringComparison.CurrentCulture) - X.IndexOf("<b>", StringComparison.CurrentCulture) + 4);
            }
            if (X.Contains("span"))
            {
                X = X.Remove(X.IndexOf("<span>", StringComparison.CurrentCulture), X.IndexOf("</span>", StringComparison.CurrentCulture) - X.IndexOf("<span>", StringComparison.CurrentCulture) + 7);
            }
            X = X.Trim();
            user.FirstName = X.Substring(0, X.IndexOf(' '));
            user.LastName = X.Substring(X.LastIndexOf(' '));
            user.Nickname = X.Substring(X.IndexOf(' '), X.LastIndexOf(' ') - X.IndexOf(' '));
            if (Converted.IndexOf("<div id=\"leftColumn\">", StringComparison.CurrentCulture) != -1)
            {
                Converted = Converted.Remove(0, Converted.IndexOf("<div id=\"leftColumn\">", StringComparison.CurrentCulture));
                var Url = Converted.Substring(Converted.IndexOf("src=", StringComparison.CurrentCultureIgnoreCase) + 4);
                Url = Url.Remove(Url.IndexOf(' '));
                Url = Url.Replace("\"", "").Replace("'", "");
                if (Url.StartsWith("images/question", StringComparison.CurrentCulture)) Url = "http://vkontakte.ru/images/question_b.gif";
                if (!Url.EndsWith("_null.gif", StringComparison.CurrentCulture))
                    user.Photo = new Downloadable() { Uri = new Uri(Url, UriKind.Absolute) };
            }
            if (Converted.Contains("<a id=\"activity_text"))
            {
                var Activity = Converted.Substring(Converted.IndexOf("<a id=\"activity_text", StringComparison.CurrentCulture));
                Activity = Activity.Remove(Activity.IndexOf("</a>", StringComparison.CurrentCulture)).Remove(0, Activity.IndexOf('>') + 1);
                user.Status = Activity;
            }
            if (Converted.Contains("<div id=\"userProfile\" class=\"clearFix\" style=\"background: #fff\">\n <div style='font-size:14px; margin:100px auto; text-align: center; height: 200px'>\n  Страница удалена ее владельцем. \n </div>\n</div>\n"))
            {
                user.IsDeleted = true;
                return;
            }
            Converted = Converted.Remove(0, Converted.IndexOf("<div id=\"rightColumn\">", StringComparison.CurrentCulture));
            Converted = Converted.Remove(0, Converted.IndexOf("<div class=\"basicInfo\">", StringComparison.CurrentCulture));
            var Table = Converted.Remove(Converted.IndexOf("</table>", StringComparison.CurrentCulture)).Remove(0, Converted.IndexOf("<table", StringComparison.CurrentCulture));
            #region basicInfo
            if (!Table.Contains("<td class=\"label\">Пол:</td>")) user.Gender = Gender.None;
            if (!Table.Contains("<td class=\"label\">Семейное положение:</td>")) user.Relation = null;
            if (!Table.Contains("<td class=\"label\">День рождения:</td>")) user.BirthDay = default(DateTime);
            if (!Table.Contains("<td class=\"label\">Родной город:</td>")) user.HomeCity = "";
            if (!Table.Contains("<td class=\"label\">Полит. взгляды:</td>")) user.Politic = "";
            if (!Table.Contains("<td class=\"label\">Религ. взгляды:</td>")) user.Religion = "";
            while (Table.IndexOf("<tr", StringComparison.CurrentCulture) >= 0)
            {
                var Key = Table.Remove(0, Table.IndexOf("<td class=\"label\">", StringComparison.CurrentCulture));
                Key = Key.Remove(Key.IndexOf("</td>", StringComparison.CurrentCulture)).Remove(0, Key.IndexOf('>') + 1);
                var Value = Table.Remove(0, Table.IndexOf("<td class=\"data\">", StringComparison.CurrentCulture) + 17);
                Value = Value.Remove(Value.IndexOf("</td>", StringComparison.CurrentCulture));
                Value = Value.Remove(0, Value.IndexOf("<div class=\"dataWrap\">", StringComparison.CurrentCulture) + 22);
                Value = Value.Remove(Value.LastIndexOf("</div>", StringComparison.CurrentCulture));
                Table = Table.Remove(0, Table.IndexOf("</tr>", StringComparison.CurrentCulture) + 1);
                switch (Key)
                {
                    case "Пол:":
                        {
                            if (Value.Contains("мужской")) user.Gender = Gender.Male;
                            else if (Value.Contains("женский")) user.Gender = Gender.Female;
                            else user.Gender = Gender.None;
                        }; break;
                    case "Семейное положение:":
                        {
                            if (Value.IndexOf("state=", StringComparison.CurrentCulture) >= 0)
                            {
                                string State = Value.Substring(Value.IndexOf("state=", StringComparison.CurrentCulture) + 6);
                                State = State.Remove(State.IndexOf('\''));
                                int r;
                                if (int.TryParse(State, out r))
                                {
                                    user.Relation = new Relation() { RelationType = (RelationType)r };
                                }
                            }
                            else
                            {
                                string id = Value.Substring(Value.IndexOf("<a", StringComparison.CurrentCulture), Value.LastIndexOf('\'') - Value.IndexOf("<a", StringComparison.CurrentCulture));
                                id = id.Remove(0, id.IndexOf('\'') + 1);
                                id = id.Remove(0, 2);
                                int rid;
                                if (int.TryParse(id, out rid))
                                {
                                    RelationType val = RelationType.Free;
                                    if (Value.Contains("встречается")) val = RelationType.HaveAFriend;
                                    if (Value.Contains("плохо")) val = RelationType.AllBad;
                                    if (Value.Contains("молвлен")) val = RelationType.Affianced;
                                    user.Relation = new Relation() { With = Human.GetHuman(rid), RelationType = val };
                                }
                            }
                        }; break;
                    case "День рождения:":
                        {
                            if (Value.IndexOf("day=", StringComparison.CurrentCulture) != -1)
                            {
                                string Day = Value.Substring(Value.IndexOf("day=", StringComparison.CurrentCulture) + 4);
                                Day = Day.Remove(Day.IndexOf('&'));
                                if (Value.IndexOf("month=", StringComparison.CurrentCulture) != -1)
                                {
                                    string Month = Value.Substring(Value.IndexOf("month=", StringComparison.CurrentCulture) + 6);
                                    Month = Month.Remove(Month.IndexOf('\''));
                                    if (Value.IndexOf("year=", StringComparison.CurrentCulture) != -1)
                                    {
                                        string Year = Value.Substring(Value.IndexOf("year=", StringComparison.CurrentCulture) + 5);
                                        Year = Year.Remove(Year.IndexOf('\''));
                                        int r;
                                        if (int.TryParse(Day, out r) && int.TryParse(Month, out r) && int.TryParse(Year, out r))
                                        {
                                            try
                                            {
                                                user.BirthDay = new DateTime(int.Parse(Year, CultureInfo.InvariantCulture), int.Parse(Month, CultureInfo.InvariantCulture), int.Parse(Day, CultureInfo.InvariantCulture));
                                            }
                                            catch
                                            {
                                            }
                                        }
                                    }
                                }
                            }
                        }; break;
                    case "Родной город:":
                        {
                            var Str = Value;
                            while (Str.Contains('>') && Str.Contains('<')) Str = Str.Remove(Str.IndexOf('<'), Str.IndexOf('>') - Str.IndexOf('<') + 1).Trim();
                            user.HomeCity = Str;
                        }; break;
                    case "Полит. взгляды:":
                        {
                            user.Politic = Value.Remove(Value.LastIndexOf("</a>", StringComparison.CurrentCulture)).Remove(0, Value.IndexOf('>') + 1);
                        }; break;
                    case "Религ. взгляды:":
                        {
                            user.Religion = Value.Remove(Value.LastIndexOf("</a>", StringComparison.CurrentCulture)).Remove(0, Value.IndexOf('>') + 1);
                        }; break;
                    default: break;
                }
            }
            #endregion
            Converted = Converted.Remove(0, Converted.IndexOf("<div id=\"personal\" class=\"flexOpen\">", StringComparison.CurrentCulture));
            Table = Converted.Remove(Converted.IndexOf("</table>", StringComparison.CurrentCulture)).Remove(0, Converted.IndexOf("<table", StringComparison.CurrentCulture));
            #region personal
            if (!Table.Contains("<td class=\"label\">Город:</td>")) user.City = "";
            if (!Table.Contains("<td class=\"label\">Моб. телефон:</td>")) user.MobilePhone = "";
            if (!Table.Contains("<td class=\"label\">Дом. телефон:</td>")) user.HomePhone = "";
            if (!Table.Contains("<td class=\"label\">ICQ:</td>")) user.ICQ = "";
            if (!Table.Contains("<td class=\"label\">Веб-сайт:</td>")) user.PersonalSite = "";
            if (!Table.Contains("<td class=\"label\">Никнейм:</td>")) user.ForumNickname = null;
            while (Table.IndexOf("<tr", StringComparison.CurrentCulture) >= 0)
            {
                var Key = Table.Remove(0, Table.IndexOf("<td class=\"label\">", StringComparison.CurrentCulture));
                Key = Key.Remove(Key.IndexOf("</td>", StringComparison.CurrentCulture)).Remove(0, Key.IndexOf('>') + 1).Trim();
                var Value = Table.Remove(0, Table.IndexOf("<td class=\"data\">", StringComparison.CurrentCulture) + 17);
                Value = Value.Remove(Value.IndexOf("</td>", StringComparison.CurrentCulture));
                Value = Value.Remove(0, Value.IndexOf("<div class=\"dataWrap\">", StringComparison.CurrentCulture) + 22);
                Value = Value.Remove(Value.LastIndexOf("</div>", StringComparison.CurrentCulture)).Trim();
                Table = Table.Remove(0, Table.IndexOf("</tr>", StringComparison.CurrentCulture) + 1);
                switch (Key)
                {
                    case "Город:":
                        {
                            user.City = Value.Remove(Value.LastIndexOf('<')).Remove(0, Value.IndexOf('>') + 1);
                        } break;
                    case "Моб. телефон:":
                        {
                            user.MobilePhone = Value;
                        } break;
                    case "Дом. телефон:":
                        {
                            user.HomePhone = Value;
                        } break;
                    case "ICQ:":
                        {
                            user.ICQ = Value;
                        } break;
                    case "Веб-сайт:":
                        {
                            user.PersonalSite = VKontakteAPI.StripTags(Value);
                        } break;
                    case "Никнейм:":
                        {

                            var W = new string[2];
                            W[0] = Value.Substring(0, Value.IndexOf('<'));
                            W[1] = Value.Substring(Value.IndexOf('>') + 1, Value.LastIndexOf('<') - Value.IndexOf('>') - 1);
                            user.ForumNickname = W;
                        } break;
                }
            }
            #endregion
            Converted = Converted.Remove(0, Converted.IndexOf("Личная информация", StringComparison.CurrentCulture));
            Table = Converted.Remove(Converted.IndexOf("</table>", StringComparison.CurrentCulture)).Remove(0, Converted.IndexOf("<table", StringComparison.CurrentCulture));
            #region personal2
            if (!Table.Contains("<td class=\"label\">Деятельность:</td>")) user.Occupy = "";
            if (!Table.Contains("<td class=\"label\">Интересы:</td>")) user.Interests = "";
            if (!Table.Contains("<td class=\"label\">Любимая музыка:</td>")) user.FavoriteMusic = "";
            if (!Table.Contains("<td class=\"label\">Любимые фильмы:</td>")) user.FavoriteFilms = "";
            if (!Table.Contains("<td class=\"label\">Любимые телешоу:</td>")) user.FavoriteTV = "";
            if (!Table.Contains("<td class=\"label\">Любимые книги:</td>")) user.FavoriteBooks = "";
            if (!Table.Contains("<td class=\"label\">Любимые игры:</td>")) user.FavoriteGames = "";
            if (!Table.Contains("<td class=\"label\">Любимые цитаты:</td>")) user.FavoriteQuotes = "";
            if (!Table.Contains("<td class=\"label\">О себе:</td>")) user.About = "";

            while (Table.IndexOf("<tr", StringComparison.CurrentCulture) >= 0)
            {
                var Key = Table.Remove(0, Table.IndexOf("<td class=\"label\">", StringComparison.CurrentCulture));
                Key = Key.Remove(Key.IndexOf("</td>", StringComparison.CurrentCulture)).Remove(0, Key.IndexOf('>') + 1).Trim();
                var Value = Table.Remove(0, Table.IndexOf("<td class=\"data\">", StringComparison.CurrentCulture) + 17);
                Value = Value.Remove(Value.IndexOf("</td>", StringComparison.CurrentCulture));
                Value = Value.Remove(0, Value.IndexOf("<div class=\"dataWrap\">", StringComparison.CurrentCulture) + 22);
                Value = Value.Remove(Value.LastIndexOf("</div>", StringComparison.CurrentCulture)).Trim();
                Table = Table.Remove(0, Table.IndexOf("</tr>", StringComparison.CurrentCulture) + 1);
                switch (Key)
                {
                    case "Деятельность:":
                        {
                            user.Occupy = (Value);
                        } break;
                    case "Интересы:":
                        {
                            user.Interests = (Value);
                        } break;
                    case "Любимая музыка:":
                        {
                            user.FavoriteMusic = (Value);
                        } break;
                    case "Любимые фильмы:":
                        {
                            user.FavoriteFilms = (Value);
                        } break;
                    case "Любимые телешоу:":
                        {
                            user.FavoriteTV = (Value);
                        } break;
                    case "Любимые книги:":
                        {
                            user.FavoriteBooks = (Value);
                        } break;
                    case "Любимые игры:":
                        {
                            user.FavoriteGames = (Value);
                        } break;
                    case "Любимые цитаты:":
                        {
                            user.FavoriteQuotes = (Value.Replace("<br>", "\r\n"));
                        } break;
                    case "О себе:":
                        {
                            user.About = (Value.Replace("<br>", "\r\n"));
                        } break;
                }
            }
            #endregion
        }

        /// <summary>
        /// Получает основную информацию для конкретного пользователя
        /// </summary>
        /// <param name="user">Пользователь, для которого надо получить список друзей</param>
        private static Thread UpdateUserProfile(Human user)
        {
            var LThread = new Thread(() =>
                {
                    try
                    {
                        var Converted = VKontakteAPI.GetPage("id" + user.Id, 2);
                        if (Converted.StartsWith("Ошибка", StringComparison.CurrentCulture))
                            return;
                        Converted = Converted.Remove(0, Converted.IndexOf(@"<div id=""pageBody"" class=""pageBody"">", StringComparison.CurrentCulture));
                        var X = Converted.Substring(Converted.IndexOf("<h1>", StringComparison.CurrentCulture) + 4, Converted.IndexOf("</h1>", StringComparison.CurrentCulture) - Converted.IndexOf("<h1>", StringComparison.CurrentCulture) - 4).Trim();
                        if (X == "Поиск людей")
                        {
                            ParseClosedProfileHTML(user, Converted);
                        }
                        else
                        {
                            ParseOpenProfileHTML(user, Converted);
                        }
                    }
                    catch (Exception e)
                    {
                        DebugLog.DebugException(e);
                    }
                });
            return LThread;
        }

        /// <summary>
        /// Обновляет профиль пользователя
        /// </summary>
        /// <param name="user">Человек, которого обновляем</param>
        public static Thread UpdateUser(Human user, bool IsFull)
        {
            var LThread = new Thread(() =>
            {
                user.UpdateTime = DateTime.Now;
                var t1 = UpdateUserProfile(user);
                int LoadedCount = 1;
                App.Scheduler.Enqueue(t1, ThreadPriority.AboveNormal, () => { return "Получение основных данных пользователя №" + user.Id + "(" + user.ToString() + ")"; }, () => { LoadedCount--; });
                if (IsFull)
                {
                    var t2 = UpdateUserFriends(user);
                    LoadedCount++;
                    App.Scheduler.Enqueue(t2, ThreadPriority.AboveNormal, () => { return "Получение списка друзей пользователя №" + user.Id + "(" + user.ToString() + ")"; }, () => { LoadedCount--; });
                }
                while (LoadedCount > 0) Thread.CurrentThread.Join(100);
                user.Loaded = user.UpdateTime;
                user.ProcessMessages();
                user.PropertyChangedCaller("Loaded");
                user.IsLoading = false;
            });
            return LThread;
        }

        /// <summary>
        /// Список реализованных в клиенте кнопок
        /// </summary>
        static public VKButton[] MadeOwn = {
                                         new VKButton() { Text = "Моя Страница", Url = "profile.php" },
                                         new VKButton() { Text = "Мои Аудиозаписи", Url="audio.php"},
                                         new VKButton() { Text = "Мои Друзья", Url = "friend.php" }
                                     };

        /// <summary>
        /// Получает список кнопок
        /// </summary>
        private static void GetVKButtons()
        {
           if (App.IsOffline)
            {
                if (VKButtons != null)
                {
                    VKButtons.Clear();
                    foreach (var v in MadeOwn) VKButtons.Add(v);
                }
                return;
            }
            var str = GetPage("blank.php",5,true);
            if (str == null) return;
            if (str.StartsWith("Ошибка", StringComparison.CurrentCulture))
            {
                MessageBox.Show(str);
                return;
            }
            str = str.Remove(0, Math.Min(str.IndexOf("<ol id='nav'>", StringComparison.CurrentCulture),str.Length));
            str = str.Remove(str.IndexOf("</ol>", StringComparison.CurrentCulture));
            while (str!=null && str.IndexOf("<a href=", StringComparison.CurrentCulture) != -1)
            {
                VKButton vb = new VKButton();
                var Link = str.Remove(str.IndexOf("</a>", StringComparison.CurrentCulture));
                str = str.Remove(0, Math.Min(str.IndexOf("</a>", StringComparison.CurrentCulture) + 1, str.Length));
                if (Link != null)
                {
                    Link = Link.Remove(0, Math.Min(Link.Length, Link.IndexOf("<a", StringComparison.CurrentCulture)));
                    Link = Link.Remove(0, Math.Min(Link.Length, Link.IndexOf('\'') + 1));
                    vb.Url = Link.Remove(Link.IndexOf('\''));
                    if (vb.Url.LastIndexOfAny(new char[] { '&', '?' }) > 0)
                        vb.Url = vb.Url.Remove(vb.Url.LastIndexOfAny(new char[] { '&', '?' }));
                    if (vb.Url != null && vb.Url.StartsWith("/", StringComparison.CurrentCulture)) vb.Url = vb.Url.Remove(0, 1);
                    vb.Text = StripTags(Link.Remove(0, Math.Min(Link.IndexOf('>') + 1, Link.Length)));
                    if (vb.Text == "ред.") vb.Text = "Ред. страницу";
                    if (VKButtons.Where(v => v != null && v.Text == vb.Text && v.Url == vb.Url).Count() == 0)
                    {
                        VKButtons.Add(vb);
                    }
                }
            }
        }
    }
}
